home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gwu / adahelp.c < prev    next >
Text File  |  1996-01-30  |  30KB  |  1,071 lines

  1. /*
  2.  
  3.   HELP ENGINE PARA GWADA
  4.  
  5.   Módulo ADAHELP.C
  6.   Programa para mostrar helps referentes à linguagem ADA.
  7.   O arquivo de help GWADA.HLP deve ser gerado através do
  8.   programa ADAHCONV.EXE.
  9.  
  10.   Trabalho de conclusao
  11.   Bacharelado em Informática
  12.  
  13.   Ulrich Peters
  14.   Rafael Presotto
  15.   Jerry Dressler
  16.  
  17.   Revisoes:
  18.     /03 Início do trabalho
  19.     /04 Reformulaçao completa do sistema de acesso ao help, definiçao do
  20.     ambiente da Help-Engine (janela/sombra/botoes...)
  21.     /05 Introduçao das funçoes de mouse
  22.     /06 Barra de rolagem e ativaçao desta pelo mouse, testes dos desvios
  23.     /08 Testes com alocaçao estática/dinâmica de memória - erro
  24.     provável no tamanho do registro de linha de help
  25.   15/08 Verificaçao do sistema gráfico acoplado - atributos de sublinhado
  26.     e highlight para monitores MDA/Hercules e cores para sist. coloridos
  27.   09/09 Revisao das funçoes do mouse para o caso de driver nao estar instalado
  28.   13/09    Volta para a mesma posiçao (scroll) anterior ao ativar ALT-F1,
  29.     modificaçao das mensagens de erro, início das procuras por strings
  30.     passados como parâmetro de chamada
  31.   16/09 Correçao no vetor de chamadas de help (31 posiçoes em vez de 30!)
  32.     /10 Excecuçao da procura de tokens, montar tokenbuffer (help virtual) para
  33.     o string passado como parâmetro, desvio direto para help se houver
  34.     apenas um desvio localizado.
  35.     /11 Revisao completa nas estruturas de alocacao dinâmica e testes finais
  36. */
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <conio.h>
  41. #include <string.h>
  42. #include <alloc.h>
  43. #include <dos.h>
  44. #include <ctype.h>
  45. #include "..\source\gwadahlp.h"
  46. #include "..\source\adavio.h"
  47. #include "..\source\mouse.h"
  48.  
  49. #define destaca_desvio(pointer)  (VioColor(pointer->screen_Xi,pointer->screen_Y+scroll, pointer->screen_Xf,pointer->screen_Y+scroll, attrib.select))
  50. #define desmarca_desvio(pointer) (VioColor(pointer->screen_Xi,pointer->screen_Y+scroll, pointer->screen_Xf,pointer->screen_Y+scroll, attrib.desvio))
  51.  
  52. /* Estrutura usada para guardar uma linha de texto de auxílio */
  53. typedef struct helpline
  54. {
  55.  struct helpline *prox;
  56.  char    helptext[77];
  57. };
  58.  
  59. /* Estrutura única para guardar os vários atributos de cor usados */
  60. typedef struct cores
  61. {
  62.  char normal;    /* texto normal do help */
  63.  char hilight;  /* texto destacado */
  64.  char desvio;   /* texto de desvio */
  65.  char dimmed;   /* texto escuro (inativo) */
  66.  char select;   /* texto selecionado */
  67.  char slider0;  /* barra de rolagem */
  68.  char slider1;  /* cursor da barra de rolagem */
  69. };
  70.  
  71. /* listas globais */
  72. struct desvio *desvio_mostrado;
  73. struct helpline *hlptxt;
  74. struct cores attrib;
  75.  
  76. int chamadas[31];    /* vetor das chamadas efetuadas p/ backtracking */
  77. int cham_scr[31];       /* vetor da posiçao do help na tela */
  78. int chmds;        /* número de chamadas de helps anteriores */
  79.  
  80. /* outras variáveis globais */
  81. FILE *help;            /* arquivo GWADA.HLP */
  82. int mouse=0;            /* controle: driver instalado? */
  83. int ha_desvio;
  84. int sliderpos;            /* posiçao do slider */
  85. int ALT_F1, TAB, ENTER;        /* variáveis para controlar os buttons */
  86. int scroll_pos;            /* posiçao do help na tela */
  87. char far *tokenbuffer;        /* buffer que simula help de tokens achados */
  88. int tokenlines;            /* linhas achadas por search() */
  89.  
  90. /* Funçoes de controle do mouse */
  91. void mouse_on(void)
  92. {
  93.  if (mouse)
  94.   mouse_enable();
  95. }
  96.  
  97. void mouse_off(void)
  98. {
  99.  if (mouse)
  100.   mouse_disable();
  101. }
  102.  
  103. /* Rotina para terminar com erro */
  104. void end(char *texto, int exitcode)
  105. {
  106.  int posicao;
  107.  char pre[70];
  108.  if (texto != "")
  109.  {
  110.   if (exitcode != 2)
  111.    strcpy(pre,"Memory Fault: ");
  112.   else
  113.    strcpy(pre,"");
  114.   strcat(pre,texto);
  115.   posicao = 40-strlen(pre)/2;
  116.   VioSombra(posicao-1,9,45+(40-posicao),13);
  117.   VioFill(posicao-3,8,43+(40-posicao),12,' ',0x4F);
  118.   VioFrame(posicao-3,8,43+(40-posicao),12,0,0x4F);
  119.   VioPrint(posicao,10,0x4F,0,pre);
  120.   while (! kbhit());
  121.  }
  122.  while (kbhit())
  123.   posicao = getch();    /* Limpar buffer do teclado */
  124.  VioWinClose(1);    /* Fechar janela e restaura tela */
  125.  _setcursortype(_NORMALCURSOR); /* retornar cursor */
  126.  exit(exitcode);
  127. }
  128.  
  129. /* Sinal acústico para erro */
  130. void beep(void)
  131. {
  132.  sound(500);
  133.  delay(10);
  134.  nosound();
  135. }
  136.  
  137. /* Buscar lista de helps disponíveis do disco
  138.    (Informaçoes do cabeçalho do arquivo)      */
  139. void ler_nodos(void)
  140. {
  141.  int qtde;    /* número de nodos */
  142.  int i;
  143.  struct tree *nodo_antes;
  144.  
  145.  raiz = NULL;
  146.  fread(&qtde,2,1,help);        /* recuperar número de nodos do arquivo */
  147.  nodo_antes = NULL;
  148.  nodo_atual = malloc(sizeof(struct tree));
  149.  for (i=0;i<qtde;i++)        /* recuperar os nodos no início do help */
  150.  {
  151.   fread(&nodo_atual->number,2,1,help);
  152.   fread(&nodo_atual->lines,2,1,help);
  153.   fread(&nodo_atual->size,4,1,help);
  154.   fread(&nodo_atual->offset,4,1,help);
  155.   nodo_atual-> prox = NULL;
  156.   if (raiz == NULL) raiz = nodo_atual;
  157.   nodo_antes = nodo_atual;
  158.   nodo_atual = malloc(sizeof(struct tree));
  159.   nodo_antes->prox = nodo_atual;
  160.  }
  161.  nodo_antes->prox = NULL;
  162.  free(nodo_atual);        /* eliminar a última criaçao de nodo */
  163. }
  164.  
  165. /* Extrair do buffer de memória o texto do help,
  166.    montando a lista encadeada dos desvios e
  167.    a lista de texto de help (scrolling)        */
  168. void process_buffer(char far *buffer, int linhas)
  169. {
  170.  int pos, n, x, i;
  171.  char numero[5];
  172.  struct helpline *texto, *linha_anterior;
  173.  
  174.  /* Inicializa ponteiros da listas */
  175.  hlptxt = NULL; /* raiz dos helps */
  176.  draiz = NULL;  /* raiz dos desvios */
  177.  braiz = NULL;  /* raiz dos brancos */
  178.  linha_anterior = NULL;
  179.  desvio_antes = NULL;
  180.  branco_antes = NULL;
  181.  i=0;
  182.  
  183.  for (x=0;x<linhas;x++)
  184.  {
  185.   /* alocar memória para a texto */
  186.   texto = (struct helpline *)farmalloc(sizeof(struct helpline));
  187.   if (texto == NULL)
  188.    end("HELPLINE",1);
  189.   pos = 0;
  190.   while (buffer[i] != '\n')
  191.   {
  192.    if (buffer[i] == '\\')    /* início de sequência de controle */
  193.    {
  194.     switch (buffer[++i])
  195.     {
  196.      case 'u' : /* alocar nodo na árvore de brancos */
  197.         i++;
  198.         branco_atual = (struct branco *)farmalloc(sizeof(struct branco));
  199.         if (branco_atual == NULL)
  200.          end("HILIGHTED TEXT LIST",1);
  201.         branco_atual->screen_Xi = pos+2;
  202.         branco_atual->screen_Y  = x+2;    /* 2 = margem da moldura! */
  203.         while ((buffer[i] != '\\')&&(pos < 76))
  204.          texto->helptext[pos++] = buffer[i++];
  205.         branco_atual->screen_Xf = pos+1;
  206.         i += 2;
  207.         branco_atual->prox = NULL;
  208.         if (braiz == NULL)
  209.          braiz = branco_atual;
  210.         if (branco_antes != NULL)
  211.          branco_antes->prox = branco_atual;
  212.         branco_antes = branco_atual;
  213.         break;
  214.      case 'v' : /* alocar nodo da arvore de desvios */
  215.         i++;
  216.         desvio_atual = (struct desvio *)farmalloc(sizeof(struct desvio));
  217.         if (desvio_atual == NULL)
  218.          end("TRANSFER LIST",1);
  219.         desvio_atual->screen_Xi = pos+2;
  220.         desvio_atual->screen_Y  = x+2;    /* 2 = margem da moldura! */
  221.         while ((buffer[i] != '\\')&&(pos < 76))
  222.          texto->helptext[pos++] = buffer[i++];
  223.         desvio_atual->screen_Xf = pos+1;
  224.         i += 2;            /* pular o '\v' */
  225.         /* extrair o número do desvio */
  226.         n=0;
  227.         while (buffer[i] != '.')
  228.         numero[n++] = buffer[i++];
  229.         i++;            /* pular o '.' */
  230.         numero[n] = '\0';
  231.         desvio_atual->number = atoi(numero);
  232.         if (numero == 0)    /* linha invalida: apaga destaque */
  233.          free(desvio_atual);
  234.         else
  235.         {
  236.          desvio_atual->prox = NULL;
  237.          if (draiz == NULL)
  238.           draiz = desvio_atual;
  239.          if (desvio_antes != NULL)
  240.           desvio_antes->prox = desvio_atual;
  241.          desvio_antes = desvio_atual;
  242.         }
  243.         break;
  244.  
  245.     }
  246.    }
  247.    if (pos < 76)
  248.     texto->helptext[pos++] = buffer[i];
  249.    i++;
  250.   }
  251.   /* encontrou um caractere \n */
  252.   i++;
  253.   if (pos)
  254.    texto->helptext[pos-1] = '\0';
  255.   else
  256.    texto->helptext[pos] = '\0';
  257.   texto->prox = NULL;
  258.   if (hlptxt == NULL)
  259.    hlptxt = texto;
  260.   if (linha_anterior != NULL)
  261.    linha_anterior->prox = texto;
  262.   linha_anterior = texto;
  263.  }
  264. }
  265.  
  266. /* Funçoes de controle da régua de botoes */
  267. void tab(int ativar)
  268. {
  269.  mouse_off();
  270.  if (ativar)
  271.  {
  272.   TAB = 1;
  273.   VioColor(36,21,41,21,attrib.desvio); /* TAB ativo */
  274.  }
  275.  else
  276.  {
  277.   TAB = 0;
  278.   VioColor(36,21,41,21,attrib.dimmed); /* TAB inativo */
  279.  }
  280.  mouse_on();
  281. }
  282.  
  283. void enter(int ativar)
  284. {
  285.  mouse_off();
  286.  if (ativar)
  287.  {
  288.   ENTER = 1;
  289.   VioColor(52,21,57,21,attrib.desvio); /* ENTER ativo */
  290.  }
  291.  else
  292.  {
  293.   ENTER = 0;
  294.   VioColor(52,21,57,21,attrib.dimmed); /* ENTER inativo */
  295.  }
  296.  mouse_on();
  297. }
  298.  
  299. void alt_f1(int ativar)
  300. {
  301.  mouse_off();
  302.  if (ativar)
  303.  {
  304.   ALT_F1 = 1;
  305.   VioColor(17,21,23,21,attrib.desvio);
  306.  }
  307.  else
  308.  {
  309.   ALT_F1 = 0;
  310.   VioColor(17,21,23,21,attrib.dimmed);  /* ALT-F1 inativo */
  311.  }
  312.  mouse_on();
  313. }
  314.  
  315. /* Verifica posiçao do mouse na régua de botoes */
  316. int testa_limites(int ref, int lim_inf, int lim_sup, int bool)
  317. {
  318.  if ((ref >= lim_inf) && (ref <= lim_sup) && (bool))
  319.  {
  320.   mouse_off();
  321.   VioWinOpen(lim_inf,21,lim_sup,21);
  322.   VioColor(lim_inf,21,lim_sup,21,attrib.select); /* destaca botao */
  323.   mouse_on();
  324.   while ((mouse) && (buttons))    /* mantém enquanto botao pressionado */
  325.    mouse_read();
  326.   mouse_off();
  327.   VioWinClose(1);        /* copia janela de volta - apaga destaque */
  328.   mouse_on();
  329.   return(1);
  330.  }
  331.  else
  332.  return(0);
  333. }
  334.  
  335. /* Destacar desvios do texto do help na tela */
  336. void mostra_desvios(int scroll)
  337. {
  338.  ha_desvio=0;
  339.  tab(0);
  340.  desvio_atual = draiz;
  341.  while (desvio_atual != NULL) /* até final da lista... */
  342.  {
  343.   if ((desvio_atual->screen_Y + scroll > 1)&&(desvio_atual->screen_Y + scroll < 20))
  344.   {
  345.    VioColor(desvio_atual->screen_Xi,desvio_atual->screen_Y+scroll, \
  346.         desvio_atual->screen_Xf,desvio_atual->screen_Y+scroll, attrib.desvio);
  347.    ha_desvio = 1;
  348.   }
  349.   desvio_atual = desvio_atual->prox;
  350.   if (ha_desvio)
  351.    tab(1);
  352.  }
  353. }
  354.  
  355. void mostra_brancos(int scroll)
  356. {
  357.  branco_atual = braiz;
  358.  while (branco_atual != NULL)    /* até final da lista... */
  359.  {
  360.   if ((branco_atual->screen_Y + scroll > 1) && \
  361.       (branco_atual->screen_Y + scroll < 20))
  362.    VioColor(branco_atual->screen_Xi,branco_atual->screen_Y+scroll, \
  363.         branco_atual->screen_Xf,branco_atual->screen_Y+scroll, attrib.hilight);
  364.   branco_atual = branco_atual->prox;
  365.  }
  366. }
  367.  
  368. /* Mostra a barra de rolagem e desenha o slider
  369.    na posiçao correspondente a do texto atual */
  370. int mostra_barra_rolagem(int tamanho, int posicao)
  371. {
  372.  int slider, i;
  373.  posicao *= -1;
  374.  for (i=3;i<19;i++)    /* desenha barra */
  375.   VioPrint(78,i,attrib.slider0,0,"▒");
  376.  tamanho -= 18;
  377.  if (tamanho > 0)    /* calcula posiçao */
  378.  {
  379.   slider = 15*(float)((float)tamanho-(float)posicao)/((float)tamanho);
  380.   slider -= 12;
  381.   VioPrintf(78,slider,attrib.slider1,0,"%c",254);
  382.   return(slider);
  383.  }
  384.  else
  385.   return(0);
  386. }
  387.  
  388.  
  389. /* Mostrar uma janela do help atual, sendo
  390.    "scroll" o número de linhas pelo qual o texto
  391.    já foi movido para cima na tela (negativo) */
  392. int rolagem(int scroll,int linhas)
  393. {
  394.  struct helpline *linha_atual;
  395.  
  396.  int i, y;
  397.  mouse_off();
  398.  
  399.  /* limpa janela de texto */
  400.  VioFill(2,2,77,19,' ',attrib.normal);
  401.  linha_atual = hlptxt;
  402.  y = -1 * scroll;
  403.  
  404.  /* pular linhas fora da tela */
  405.  for (i=0;i<y;i++)
  406.   linha_atual = linha_atual->prox;
  407.  
  408.  /* mostrar linhas válidas */
  409.  for (i=0;((i<18)&&(linha_atual != NULL));i++)
  410.  {
  411.   VioPrint(2,i+2,attrib.normal,0,linha_atual->helptext);
  412.   linha_atual = linha_atual->prox;
  413.  }
  414.  
  415.  mostra_desvios(scroll);
  416.  mostra_brancos(scroll);
  417.  
  418.  /* se havia desvio destacado na tela, mostrar este
  419.     desvio na posiçao atual (depois da rolagem) */
  420.  if (desvio_mostrado != NULL)
  421.  {
  422.   if ((desvio_mostrado->screen_Y + scroll > 1)&&(desvio_mostrado->screen_Y + scroll < 20))
  423.   {
  424.    destaca_desvio(desvio_mostrado);
  425.    enter(1);
  426.   }
  427.   else
  428.   {
  429.    desvio_mostrado = NULL;
  430.    enter(0);
  431.   }
  432.  }
  433.  sliderpos = mostra_barra_rolagem(linhas,y);
  434.  mouse_on();
  435.  return(i);
  436. }
  437.  
  438. /* Procura por uma certa palavra no índice */
  439. int search(char *texto)
  440. {
  441.  char initial;
  442.  char linha_U[150], linha[150];
  443.  char titulo[150], tu, ti;
  444.  int x, lin, help_num, pos, index, occur, offset=0;
  445.  size_t memory;
  446.  char far *buffer_temp;
  447.  int trunc = 0;
  448.  
  449.  VioPrint(28,11,attrib.hilight,0,"Searching... please wait");
  450.  initial = toupper(texto[0]);
  451.  
  452.  /* Determina o número do help correspondente a inicial da palavra
  453.     procurada (token) */
  454.  switch (initial)
  455.  {
  456.   case 'A': help_num = 20; break;
  457.   case 'B': help_num = 21; break;
  458.   case 'C': help_num = 22; break;
  459.   case 'D': help_num = 23; break;
  460.   case 'E': help_num = 24; break;
  461.   case 'F': help_num = 25; break;
  462.   case 'G': help_num = 26; break;
  463.   case 'H': help_num = 27; break;
  464.   case 'I':
  465.   case 'J': help_num = 28; break;
  466.   case 'K':
  467.   case 'L': help_num = 29; break;
  468.   case 'M': help_num = 30; break;
  469.   case 'N': help_num = 31; break;
  470.   case 'O': help_num = 32; break;
  471.   case 'P': help_num = 33; break;
  472.   case 'Q': help_num = 34; break;
  473.   case 'R': help_num = 35; break;
  474.   case 'S': help_num = 36; break;
  475.   case 'T': help_num = 37; break;
  476.   case 'U': help_num = 38; break;
  477.   case 'V': help_num = 39; break;
  478.   case 'W': help_num = 40; break;
  479.   default : help_num = 41;      /* X, Y e Z */
  480.  }
  481.  
  482.  /* busca o help de índice correspondente... */
  483.  nodo_atual = raiz;
  484.  while ((nodo_atual->number != help_num)&&(nodo_atual != NULL))
  485.   nodo_atual = nodo_atual->prox;
  486.  memory = nodo_atual->size;
  487.  
  488.  /* aloca memória para buffer temporário e ler help */
  489.  buffer_temp = (char *)farmalloc(memory+2);
  490.  if (buffer_temp == NULL)
  491.   end("BUFFER TEMP",1);
  492.  fseek(help,nodo_atual->offset,0);
  493.  fread(buffer_temp,memory,1, help);
  494.  buffer_temp[memory] = '\0';
  495.  
  496.  /* montar argumento de procura - texto em maiúsculas */
  497.  for (x=0; x<strlen(texto); x++)
  498.   texto[x] = toupper(texto[x]);
  499.  
  500.  /* começar a procura... */
  501.  strcpy(tokenbuffer,"\\uGWAda Help Engine Token Search\\n\r\n\n");
  502.  occur = 0;
  503.  while ((occur == 0)&&(strlen(texto) > 0))
  504.  {
  505.   pos = 0;
  506.   lin = 0;
  507.   while (lin < nodo_atual->lines)    /* enquanto nao fim do help... */
  508.   {
  509.    index = 0;
  510.    while ((buffer_temp[pos] != '\n')&&(index < 80))
  511.     linha[index++] = buffer_temp[pos++];
  512.    linha[--index] = '\0';        /* final de linha */
  513.    lin++;
  514.    pos++;
  515.  
  516.    /* linha de texto extraída - agora testar argumentos! */
  517.    if (linha[0] != ' ')
  518.    {
  519.     strcpy(titulo,linha); /* salva como título, já que nao começa com espaço */
  520.     tu = 0;               /* controle: título usado = 0 */
  521.     ti = 0;            /* controle: título inserido = 0 */
  522.    }
  523.    strcpy(linha_U,linha);
  524.    for (x=0; x<strlen(linha_U); x++)
  525.     linha_U[x] = toupper(linha_U[x]); /* transforma toda linha em maiúsculas */
  526.  
  527.    if (strstr(linha_U,texto) != NULL)
  528.    {
  529.     if (linha[0] != ' ') /* é um título */
  530.      tu = 1;
  531.     else
  532.     {
  533.      if ((tu == 0)&&(ti == 0)) /* título ainda nao usado! */
  534.      {
  535.       ti = 1; /* título inserido = 1: em título si nao satisfaz token, */
  536.           /* mas um item sim, logo inserir título antes do item!   */
  537.       offset = strlen(tokenbuffer);
  538.       if (offset < 8000)
  539.       {
  540.        strcat(tokenbuffer,titulo); /* inserir título antes da linha recuada */
  541.        offset = strlen(tokenbuffer);
  542.        tokenbuffer[offset++] = '\r';
  543.        tokenbuffer[offset++] = '\n';
  544.        tokenbuffer[offset++] = '\0';
  545.        occur++;
  546.       }
  547.      }
  548.     }
  549.     offset = strlen(tokenbuffer);
  550.     if (offset < 8000)
  551.     {
  552.      strcat(tokenbuffer,linha);
  553.      offset = strlen(tokenbuffer);
  554.      tokenbuffer[offset++] = '\r';
  555.      tokenbuffer[offset++] = '\n';
  556.      tokenbuffer[offset++] = '\0';
  557.      occur++;
  558.     }
  559.     else
  560.      trunc = 1;
  561.     VioPrintf(33,13,attrib.slider0,0,"  %d bytes  ",offset);
  562.    }
  563.    else
  564.    {
  565.     /* nao satisfez a condiçao de procura, mas... */
  566.     if ((tu == 1)&&(linha[0] == ' '))
  567.     {
  568.      /* linha é um subitem de um TITULO que satisfaz a condiçao de procura! */
  569.      /* logo também deverá ser copiada */
  570.      offset = strlen(tokenbuffer);
  571.      if (offset < 8000)
  572.      {
  573.       strcat(tokenbuffer,linha);
  574.       offset = strlen(tokenbuffer);
  575.       tokenbuffer[offset++] = '\r';
  576.       tokenbuffer[offset++] = '\n';
  577.       tokenbuffer[offset++] = '\0';
  578.       occur++;
  579.      }
  580.      else
  581.       trunc = 1;
  582.     }
  583.    }
  584.   }
  585.   if (occur == 0)            /* nao achou este token, logo   */
  586.    texto[strlen(texto)-1] = '\0';    /* tentar cortar a última letra */
  587.  }                    /* para tentar de novo          */
  588.  
  589.  
  590.  if (trunc)
  591.  {
  592.   beep();
  593.   strcat(tokenbuffer,"\r\n< Search truncated >\r\n");
  594.  }
  595.  else
  596.  {
  597.   if (!occur)
  598.    strcat(tokenbuffer,"\r\n< No matches found - press \\uF1\\n >\r\n");
  599.   else
  600.    strcat(tokenbuffer,"\r\n< End >\r\n");
  601.  }
  602.  farfree(buffer_temp);
  603.  tokenlines = occur+4;
  604.  return(tokenlines);
  605. }
  606.  
  607. /* Funçao que mostra help,
  608.    retornando eventualmente um número
  609.    de outro help a ser mostrado       */
  610. int showhelp(int number, int scroll, char *token)
  611. {
  612.  size_t memory;
  613.  char far *buffer;
  614.  struct helpline *linha;
  615.  int abandonar = 0;
  616.  int retorna = 0;
  617.  unsigned char tecla;
  618.  int lines;
  619.  
  620.  scroll_pos = scroll;    /* posiçao anterior deste texto */
  621.  /* número < 0 --> mostrar o TOKENBUFFER
  622.     número > 0 --> buscar dados de arquivo */
  623.  if (number > 0)    /* ARQUIVO!!! */
  624.  {
  625.   /* Varrer a lista encadeada pelo número do help solicitado */
  626.   nodo_atual = raiz;
  627.   while ((nodo_atual->number != number)&&(nodo_atual != NULL))
  628.    nodo_atual = nodo_atual->prox;
  629.   /* Help nao existe, logo nao pode chamar outro - retornar 0 */
  630.   if (nodo_atual == NULL)
  631.    return(0);
  632.   /* Help localizado, alocar memória para texto */
  633.   memory = nodo_atual->size;
  634.   buffer = (char *)farmalloc(memory+2);
  635.   if (buffer == NULL)
  636.    end("BUFFER",1);
  637.   /* Extrair o help do arquivo */
  638.   fseek(help,nodo_atual->offset,0);
  639.   fread(buffer,memory,1, help);
  640.   buffer[memory] = '\0';
  641.   lines = nodo_atual->lines;
  642.   process_buffer(buffer,lines);
  643.   farfree(buffer);
  644.  }
  645.  else
  646.  {
  647.   if (strcmp(token,""))    /* TOKENBUFFER!!! */
  648.   tokenlines = search(token);
  649.   lines = tokenlines;
  650.   process_buffer(tokenbuffer,tokenlines);
  651.   if ((draiz != NULL)&&(draiz->prox == NULL)) /* há apenas um único desvio: */
  652.    return(draiz->number);              /* desvia diretamente!!       */
  653.  }
  654.  
  655.  
  656.  /* Os dois métodos convergem aqui:
  657.     Mostrar help na tela */
  658.  rolagem(scroll,lines);
  659.  
  660.  /* zerar ponteiros de controle... */
  661.  desvio_mostrado = NULL;
  662.  desvio_antes = NULL;
  663.  
  664.  /* Help está na tela agora, esperar pelo usuário */
  665.  if (mouse) /* há mouse instalado? */
  666.  {
  667.   mouse_enable();      /* sim, habilita */
  668.   mouse_read();
  669.  }
  670.  
  671.  while (! abandonar)
  672.  {
  673.   if (mouse)        /* testar mouse, se houver */
  674.    mouse_read();
  675.   mouse_x /= 8;
  676.   mouse_y /= 8;
  677.   if (buttons)        /* botao do mouse pressionado! E agora? */
  678.   {
  679.    if (desvio_mostrado != NULL) /* salvar este desvio... */
  680.     desvio_antes = desvio_mostrado;
  681.  
  682.    /* testar posiçao do mouse por desvio válido... */
  683.    desvio_atual = draiz;
  684.    while ((desvio_atual != NULL) \
  685.        && !((desvio_atual->screen_Y + scroll == mouse_y) \
  686.        && (desvio_atual->screen_Xi <= mouse_x)&&(desvio_atual->screen_Xf >= mouse_x) \
  687.        && (mouse_y < 20)))
  688.     desvio_atual = desvio_atual->prox;
  689.  
  690.    if (desvio_atual != NULL)
  691.    /* foi selecionado um novo desvio atraves do mouse ? */
  692.    {
  693.     if (desvio_mostrado != NULL)
  694.     /* já teve desvio marcado antes - desmarcar anterior */
  695.     desmarca_desvio(desvio_mostrado);
  696.  
  697.     /* marcar desvio atual */
  698.     mouse_off();
  699.     destaca_desvio(desvio_atual);
  700.     mouse_on();
  701.     retorna = desvio_atual->number;
  702.     abandonar = 1;
  703.     scroll_pos = scroll;
  704.     while ((mouse) && (buttons)) mouse_read();
  705.    }
  706.    /* mouse na área de rolagem? */
  707.    if ((mouse_x == 78)&&(mouse_y < 19)&&(mouse_y > 2))
  708.    {
  709.     if (mouse_y < sliderpos)
  710.      ungetch(200); /* seta para cima */
  711.     if (mouse_y > sliderpos)
  712.      ungetch(208); /* seta para baixo */
  713.    }
  714.  
  715.    /* mouse na área dos botoes? */
  716.    if (mouse_y == 21)
  717.    {
  718.     tecla = buttons;              /*  SIMULAR TECLADO!!  */
  719.     if (testa_limites(mouse_x,2,11,1))       ungetch(187); /* F1 */
  720.     if (testa_limites(mouse_x,17,31,ALT_F1)) ungetch(232); /* Alt-F1 */
  721.     if ((buttons == 1) && testa_limites(mouse_x,36,47,TAB))
  722.      tecla = ungetch(9);              /* tecla esquerda = TAB */
  723.     if ((buttons == 2) && testa_limites(mouse_x,36,47,TAB))
  724.      tecla = ungetch(143);            /* tecla direita = BACKTAB */
  725.     if (testa_limites(mouse_x,52,65,ENTER))  ungetch(13); /* ENTER */
  726.     if (testa_limites(mouse_x,70,76,1))      ungetch(27); /* ESC */
  727.    }
  728.   }
  729.  
  730.   if (kbhit())    /* nao interessa se foi teclado ou simulaçao... */
  731.   {
  732.    tecla = getch();
  733.    if (tecla == 0)
  734.     tecla = getch() + 128;
  735.    switch (tecla)
  736.    {
  737.     case   9: /* TAB - destacar o próximo desvio */
  738.          if (ha_desvio)
  739.          {
  740.           if (desvio_mostrado == NULL) /* sem campo destacado... */
  741.           {
  742.            desvio_atual = draiz;
  743.            while ((desvio_mostrado == NULL)&&(desvio_atual != NULL))
  744.            {
  745.         if ((desvio_atual->screen_Y + scroll > 1)&&(desvio_atual->screen_Y + scroll < 20))
  746.         {
  747.          destaca_desvio(desvio_atual);
  748.          desvio_mostrado = desvio_atual;
  749.          enter(1);
  750.         }
  751.         else
  752.          desvio_atual = desvio_atual->prox;
  753.            }
  754.           }
  755.           else /* já há um campo destacado */
  756.           {
  757.            desmarca_desvio(desvio_mostrado);
  758.            desvio_mostrado = desvio_mostrado->prox;
  759.            if ((desvio_mostrado != NULL)&&(desvio_mostrado->screen_Y + scroll > 1)&&(desvio_mostrado->screen_Y + scroll < 20))
  760.            {
  761.         destaca_desvio(desvio_mostrado);
  762.         enter(1);
  763.            }
  764.            else
  765.            {
  766.         desvio_mostrado = NULL; /* força o começo no início da lista */
  767.         ungetch(9);             /* simula outra entrada... */
  768.            }
  769.           }
  770.          }
  771.          else
  772.           beep(); /* Nao há nada para destacar... */
  773.          break;
  774.     case 13: /* ENTER - selecionar desvio destacado */
  775.          if (desvio_mostrado == NULL)
  776.           beep();
  777.          else
  778.          {
  779.           abandonar = 1;
  780.           retorna = desvio_mostrado->number;
  781.           scroll_pos = scroll;
  782.          }
  783.          break;
  784.     case 27: /* ESC - fim */
  785.          abandonar = 1;
  786.          break;
  787.     case 143: /* BACKTAB - destacar desvio anterior */
  788.           if (TAB) /* há desvios na tela atual? */
  789.           {
  790.            if (desvio_mostrado == NULL)
  791.            {
  792.         /* destacar o último desvio da tela atual */
  793.         desvio_atual = draiz;
  794.         while ((desvio_atual != NULL) && (desvio_atual->prox->screen_Y + scroll < 20) && (desvio_atual->prox != NULL))
  795.          desvio_atual = desvio_atual->prox;
  796.         destaca_desvio(desvio_atual);
  797.         enter(1);
  798.         desvio_mostrado = desvio_atual;
  799.            }
  800.            else
  801.            {
  802.         /* já havia desvio ativo - destacar o anterior... */
  803.         desvio_atual = draiz;
  804.         if (desvio_atual == desvio_mostrado)
  805.         {
  806.          /* a raíz estava ativa - desmarcar */
  807.          desmarca_desvio(desvio_atual);
  808.          desvio_mostrado = NULL;
  809.          ungetch(143); /* simula BACKTAB */
  810.         }
  811.         else
  812.         {
  813.          /* algum desvio diferente da raíz ativo... */
  814.          while (desvio_atual->prox != desvio_mostrado)
  815.           desvio_atual = desvio_atual->prox;
  816.          /* testar se o desvio é válido para a tela atual... */
  817.          if (desvio_atual->screen_Y + scroll > 1)
  818.          {
  819.           destaca_desvio(desvio_atual);
  820.           desvio_mostrado = desvio_atual;
  821.           desvio_atual = desvio_atual->prox;
  822.           desmarca_desvio(desvio_atual);
  823.           enter(1);
  824.          }
  825.          else
  826.          {
  827.           /* desvio anterior nao é válido - simular BACKTAB */
  828.           desmarca_desvio(desvio_mostrado);
  829.           desvio_mostrado = NULL;
  830.           ungetch(143);
  831.          }
  832.         }
  833.            }
  834.           }
  835.           else
  836.            beep();
  837.           break;
  838.     case 187: /* F1 - mostra help #1 */
  839.           abandonar = 1;
  840.           retorna = 1;
  841.           scroll_pos = scroll;
  842.           break;
  843.     case 199: /* home - vai até o início do texto */
  844.           if (scroll)
  845.           {
  846.            scroll = 0;
  847.            rolagem(scroll,lines);
  848.           }
  849.           else
  850.            beep();
  851.           break;
  852.     case 200: /* seta para cima */
  853.           if (scroll < 0)
  854.            rolagem(++scroll,lines);
  855.           else
  856.            beep();
  857.           break;
  858.     case 201: /* PgUp */
  859.           if (scroll < 0)
  860.           {
  861.            if (scroll < -18)
  862.         scroll += 18;        /* sobe uma página */
  863.            else
  864.         scroll = 0;        /* vai até o início */
  865.            rolagem(scroll,lines);
  866.           }
  867.           else
  868.            beep();
  869.           break;
  870.     case 207: /* end - vai até o final do texto */
  871.           if (lines > 18 + -1 * scroll)
  872.           {
  873.            scroll = 18 - lines;
  874.            rolagem(scroll,lines);
  875.           }
  876.           else
  877.            beep();
  878.           break;
  879.     case 208: /* seta para baixo */
  880.           if (lines > 18 + -1 * scroll)
  881.            rolagem(--scroll,lines);
  882.           else
  883.            beep();
  884.           break;
  885.     case 209: /* PgDn */
  886.           if (lines > 18 + -1 * scroll)
  887.           {
  888.            if (lines > 36 + -1 * scroll)
  889.         scroll -= 18;        /* desce uma página */
  890.            else
  891.         scroll = 18 - lines;    /* vai até o final */
  892.            rolagem(scroll,lines);
  893.           }
  894.           else
  895.            beep();
  896.           break;
  897.     case 232: /* ALT-F1 */
  898.           if (chmds > 0)
  899.           {
  900.            abandonar = 1;
  901.            retorna = chamadas[--chmds];
  902.            scroll_pos = cham_scr[chmds];
  903.           }
  904.           else
  905.            beep();
  906.          if (chmds == 0)
  907.            alt_f1(0);
  908.          break;
  909.    } /* termina switch */
  910.   }  /* termina if kbhit() */
  911.  }   /* abandonar! */
  912.  
  913.  /* Liberar memória alocada para as listas... */
  914.  linha = hlptxt;
  915.  while (linha != NULL)
  916.  {
  917.   hlptxt = linha;
  918.   linha = linha->prox;
  919.   farfree(hlptxt);
  920.  }
  921.  
  922.  desvio_atual = draiz;
  923.  while (desvio_atual != NULL)
  924.  {
  925.   draiz = desvio_atual;
  926.   desvio_atual = desvio_atual->prox;
  927.   farfree(draiz);
  928.  }
  929.  
  930.  branco_atual = braiz;
  931.  while (branco_atual != NULL)
  932.  {
  933.   braiz = branco_atual;
  934.   branco_atual = branco_atual->prox;
  935.   farfree(braiz);
  936.  }
  937.  
  938.  /* volta ao chamador, informando o número do help escolhido
  939.     nos desvios deste texto */
  940.  desvio_mostrado = NULL;
  941.  mouse_off();
  942.  return(retorna);
  943. }
  944.  
  945.  
  946.  
  947. void main(int argc, char *argv[])
  948. {
  949.  
  950.  int i, number, primeira_vez = 1;
  951.  char path[30];
  952.  
  953.  /* INICIALIZA MODULO DE ENTRADA DE VIDEO */
  954.  VioInit();
  955.  if (color)
  956.  {
  957.   attrib.normal  = 0x17; /* fundo azul com letra branca */
  958.   attrib.hilight = 0x1F; /* fundo azul com letra em branco intenso */
  959.   attrib.desvio  = 0x1E; /* fundo azul com letra em amarelo */
  960.   attrib.dimmed  = 0x18; /* fundo azul com letra cinza */
  961.   attrib.select  = 0x3E; /* fundo ciano com letra amarela */
  962.   attrib.slider0 = 0x13; /* fundo ciano com letra azul */
  963.   attrib.slider1 = 0x31; /* fundo azul com letra ciano */
  964.  }
  965.  else
  966.  {
  967.   attrib.normal  = 0x07; /* fundo preto com letra normal */
  968.   attrib.hilight = 0x01; /* fundo preto com letra sublinhada */
  969.   attrib.desvio  = 0x0F; /* fundo preto com letra em branco intenso */
  970.   attrib.dimmed  = 0x00; /* fundo preto com letra preta */
  971.   attrib.select  = 0x70; /* fundo branco com letra preta */
  972.   attrib.slider0 = 0x07; /* fundo preto com letra branca */
  973.   attrib.slider1 = 0x70; /* fundo branco com letra preta */
  974.  }
  975.  
  976.  /* MONTA AMBIENTE DA HELP ENGINE */
  977.  VioWinOpen(0,1,79,23);
  978.  VioSombra(2,2,79,23);
  979.  VioFill(0,1,78,22,' ',attrib.normal);
  980.  if (color)
  981.  {
  982.   VioFrame(0,1,78,22,0,attrib.hilight);
  983.   VioPrint(1,20,attrib.hilight,0,VioStrep('─',77));
  984.  }
  985.  else
  986.  {
  987.   VioFrame(0,1,78,22,0,attrib.desvio);
  988.   VioPrint(1,20,attrib.desvio,0,VioStrep('─',77));
  989.  }
  990.  VioPrintf(78,2,attrib.slider0,0,"%c",24);
  991.  VioPrintf(78,19,attrib.slider0,0,"%c",25);
  992.  VioPrintf(2,21,attrib.normal,0,"F1 Summary     ALT-F1 Previous    %cTAB%c Select    ENTER Go Topic    ESC End",27,26);
  993.  VioColor(2,21,4,21,attrib.desvio);   /* F1 ativo */
  994.  alt_f1(0); /* ALT-F1 inativo */
  995.  tab(0);    /* TAB inativo */
  996.  enter(0);  /* ENTER inativo */
  997.  VioColor(70,21,73,21,attrib.desvio); /* ESC ativo */
  998.  
  999.  /* INICIALIZAÇAO */
  1000.  /* há mouse instalado? */
  1001.  _setcursortype(_NOCURSOR);
  1002.  chmds = 0;
  1003.  if (mouse_reset() == -1) mouse = 1;
  1004.  
  1005.  strcpy(path,argv[0]);
  1006.  i = strlen(path);
  1007.  while(path[i] != '\\') path[i--] = '\0';
  1008.  strcat(path,"GWADA.HLP");
  1009.  
  1010.  if ( (help = fopen(path,"rb")) == NULL)
  1011.   end("Sorry, file GWADA.HLP was not found.",2);
  1012.  
  1013.  fread(&path,sizeof(header),1,help);
  1014.  path[sizeof(header)-1] = '\0'; /* Pular a marca de final de arquivo
  1015.                    (0x1A) e terminar o string com \0 */
  1016.  if (strcmp(path,header) != 0)
  1017.   end("Sorry, help file seems to be corrupt.",2);
  1018.  
  1019.  /* Arquivo de help achado, montar agora lista encadeada
  1020.     através das informaçoes no cabeçalho do arquivo... */
  1021.  ler_nodos();
  1022.  
  1023.  /* LOOP DA CONSULTA */
  1024.  number = 1;
  1025.  chamadas[chmds] = number; /* índice 0 */
  1026.  cham_scr[chmds] = 0;       /* scroll */
  1027.  if (argc > 1)
  1028.  {
  1029.   tokenbuffer = (char *)farmalloc(8192);
  1030.   if (tokenbuffer == NULL)
  1031.    end("TOKEN BUFFER",1);
  1032.  }
  1033.  while (number)
  1034.  {
  1035.   enter(0);  /* ENTER desativado, pois sem campo ativo */
  1036.   if (chmds)
  1037.    alt_f1(1); /* ALT-F1 ativo, pois há para onde voltar */
  1038.  
  1039.   if ((argc > 1)&&(primeira_vez))
  1040.   {
  1041.    number = -1;
  1042.    number = showhelp(number,scroll_pos,argv[1]);
  1043.    primeira_vez = 0;
  1044.    if (argc > 1) chamadas[chmds] = -1; // buffer de tokens montado
  1045.   }
  1046.   else
  1047.    number = showhelp(number,scroll_pos,"");
  1048.   if ((number != chamadas[chmds]) || (scroll_pos != cham_scr[chmds]))
  1049.   /* inclui apenas se help e/ou posicao diferente */
  1050.   {
  1051.    if (++chmds > 30)
  1052.    {
  1053.     chmds = 30;            /* sao mais de trinta consultas... */
  1054.     for (i=0;i<30;i++)        /* tirar primeira posicao da pilha */
  1055.     {                /* para criar espaco para a atual */
  1056.      chamadas[i] = chamadas[i+1];
  1057.      cham_scr[i] = cham_scr[i+1];
  1058.     }
  1059.    }
  1060.    chamadas[chmds] = number;
  1061.    cham_scr[chmds-1] = scroll_pos;
  1062.    scroll_pos = 0;
  1063.   }
  1064.  }
  1065.  
  1066.  /* terminar programa normalmente */
  1067.  if ((heapcheck() != 2) || (farheapcheck() != 2))
  1068.   end("Error in (far) heap.",1);
  1069.  else
  1070.   end("",0);
  1071. }